package com.weactivity.service.impl;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.weactivity.dto.*;
import com.weactivity.entity.Activity;
import com.weactivity.entity.Resource;
import com.weactivity.exception.ActivityCreationException;
import com.weactivity.mapper.ActivityMapper;
import com.weactivity.mapper.ResourceMapper;
import com.weactivity.service.MessageService;
import com.weactivity.service.ResourceService;
import com.weactivity.utils.Constant;
import com.weactivity.utils.ConvertUtil;
import com.weactivity.utils.UserHolder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
public class ResourceServiceImpl implements ResourceService {
    @Autowired
    ResourceMapper resourceMapper;

    @Autowired
    ActivityMapper activityMapper;
    @Autowired
    MessageService messageService;

    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    //创建资源
    @Override
    public void newResource(ResourceDTO resourceDTO) {
        Resource resource = new Resource();
        BeanUtils.copyProperties(resourceDTO, resource);
        resource.setAid(-1);
        resource.setStage(-1);
        resource.setAppoint_time(LocalDateTime.now());
        resource.setBeginTime(LocalDateTime.now());
        resource.setEndTime(LocalDateTime.now());
        resourceMapper.insert(resource);


    }

    //分页查询
    @Override
    public PageResult pageQuery(PageQueryDTO pageQueryDTO) {
        PageHelper.startPage(pageQueryDTO.getPage(), pageQueryDTO.getPageSize());
        Page<ResourceDTO> page = resourceMapper.pageQuery(pageQueryDTO);
        return new PageResult(page.getTotal(), page.getResult());

    }

    //预约资源
    @Override
    public void reserve(ReserveDTO reserveDTO) {
        Resource resource = new Resource();
        BeanUtils.copyProperties(reserveDTO, resource);
        resourceMapper.update(resource);

    }

    @Override
    public void updateById(Integer id) {
        resourceMapper.updateById(id);
    }

    /**
     * 根据resourceInfo和活动时间段判断是否有活动与其冲突,返回冲突资源列表和可用资源列表
     * @param resourceInfo
     * @param actBeginTime
     * @param actEndTime
     * @return
     */

    @Override
    public Map<String, List<Resource>> isConficted(Map<String, String> resourceInfo, LocalDateTime actBeginTime, LocalDateTime actEndTime ) {
        UserDTO userDTO = UserHolder.getUser();
        Map<String, List<Resource>> map = new HashMap<>();
        List<Resource> confictedResourceList = new LinkedList<>();
        List<Resource> usableResourceList = new LinkedList<>();
        map.put("usable", usableResourceList);
        map.put("confict", confictedResourceList);
        String resourceName = resourceInfo.get(Constant.RESOURCE_NAME);
        String resourceType = resourceInfo.get(Constant.RESOURCE_TYPE);
        String resourceImp = resourceInfo.get(Constant.RESOURCE_IMP);
        // LocalDateTime actBeginTime = LocalDateTime.parse(beginTimeStr, dateTimeFormatter);
        //LocalDateTime actEndTime = LocalDateTime.parse(endTimeStr, dateTimeFormatter);
        //活动开始日期，不包括时间
        LocalDate actBeginDate = actBeginTime.toLocalDate();
        LocalDate actEndDate = actEndTime.toLocalDate();

        //分两种情况
        //1.根据资源名查找
        //如果有资源名，说明具体指定一个资源
        //获取该资源所有的使用时间段(只取当天的使用时间段)

        if (null != resourceName) {

            System.out.println("resourceName:" + resourceName);
            System.out.println("actBeginDate:" + actBeginDate);
            List<Resource> resourceListByName = resourceMapper.selectResourceByName(resourceName, actBeginDate);
            System.out.println("size"+resourceListByName.size());
            System.out.println("resourceListByName"+resourceListByName);
            //a.如果资源没有活动占用时间冲突（不用aid判断了）
            //如果返回一个结果并且该结果的appoint = 0，则表示该具体资源在当天没有被别人使用，直接添加
            if (resourceListByName.size() == 1 && resourceListByName.get(0).getAppoint() == 0) {
                usableResourceList.add(resourceListByName.get(0));
                //这里就可以直接返回了,因为资源当天没被占用，添加到可用资源，且无冲突资源。
                return map;
            }
            //如果走到这一步，表示该资源当天有使用情况，对每个使用情况进行判断
            for (Resource i : resourceListByName) {
                LocalDateTime beginTime1 = i.getBeginTime();
                LocalDateTime endTime1 = i.getEndTime();
                //如果时间上无冲突 不做操作
                if ((actEndTime.isBefore(beginTime1) || actBeginTime.isAfter(endTime1))) {

                } else {
                    //如果有冲突，加入冲突list
                    confictedResourceList.add(i);
                }
            }
            //如果冲突list里面的元素也为空，说明这个资源可用
            //这时随便加入一个资源记录就行
            if( 0 == confictedResourceList.size()){
                usableResourceList.add(resourceListByName.get(0));
            }
            return map;
        }

        //2.根据资源类型和资源等级查找，返回某一类资源
        int resourceTypeInt = ConvertUtil.convertResourceType(resourceType);
        int resourceImpInt = ConvertUtil.convertResourceType(resourceImp);
        List<Resource> resources = resourceMapper.selectResourceByTypeAndImp(resourceTypeInt, resourceImpInt, actBeginDate);
        //查询出来的结果实例如下，可以看到需要去重
//        2			102教室	1	0		2	0	0
//        3			103教室	1	0		2	0	0
//        7	1		101教室	1	0		2	0	1	2024-05-30 21:46:00	2024-06-01 15:00:00	2024-06-01 16:00:00
//        8	1		101教室	1	0		2	0	1	2024-05-30 21:46:00	2024-06-01 12:00:00	2024-06-01 14:00:00

//        9	1		104教室	1	0		2	0	1	2024-05-30 21:46:00	2024-06-01 17:00:00	2024-06-01 19:00:00

        //中间resource记录 针对那些appoint不为0的resource
        List<Resource> mid_list = new LinkedList<>();
        for (Resource r : resources) {
            //如果appoint == 0,则资源一定可用,因为查询语句查询如果资源当天没有被占用则返回空闲状态，否则返回占用信息，
            //这个添加的是空闲资源
            if (0 == r.getAppoint()) {
                usableResourceList.add(r);
                continue;
            }
            LocalDateTime beginTime1 = r.getBeginTime();
            LocalDateTime endTime1 = r.getEndTime();
            //如果时间上无冲突,说明这个资源该这个时间段可以被使用
            if ((actEndTime.isBefore(beginTime1) || actBeginTime.isAfter(endTime1))) {
                mid_list.add(r);
            } else {
                //有冲突
                //需要把中间列表里面资源名跟冲突的资源名相同的删除
                for (Resource j : mid_list) {
                    if (j.getName().equals(r.getName())) {
                        mid_list.remove(j);
                    }
                }
                confictedResourceList.add(r);
            }
        }
        //利用HashSet，根据resource的名称去重
        Set<String> Names = new HashSet<>();
        Iterator<Resource> iterator = mid_list.iterator();
        while (iterator.hasNext()) {
            Resource resourceInMid = iterator.next();
            if (Names.add(resourceInMid.getName())) {
                //如果能添加到set中，说明没出现过
                usableResourceList.add(resourceInMid);
            }
        }
        usableResourceList.forEach(System.out::println);
        return map;
    }

    /**
     * 资源被活动占用的方法
     *
     * @param activity           创建的活动相关信息
     * @param resourceInfo       需要资源相关信息
     * @param usableResourceList 可用资源相关信息
     * @return
     */
    @Override
    public Map<String,Object> fillResourceWithAct(Activity activity, Map<String, String> resourceInfo, List<Resource> usableResourceList) {

        Map<String,Object> resultMap = new HashMap<>();
        //数据处理，将要插入数据库的数据准备好
        //-------------------------------------------
        String resourceName = resourceInfo.get(Constant.RESOURCE_NAME);
        String resourceType = resourceInfo.get(Constant.RESOURCE_TYPE);
        String resourceImp = resourceInfo.get(Constant.RESOURCE_IMP);
        int resourceTypeInt = ConvertUtil.convertResourceType(resourceType);
        int resourceImpInt = ConvertUtil.convertResourceType(resourceImp);
        int aid = activity.getId();
        LocalDateTime now = LocalDateTime.now();

        String beginTime = activity.getBeginTime();
        String endTime = activity.getEndTime();
        Resource resource = new Resource();
        resource.setAid(aid);
        resource.setType(resourceTypeInt);
        resource.setImp(resourceImpInt);
        resource.setName(resourceName);
        resource.setAppoint(Constant.RESOURCE_ISRESERVED);
        resource.setAppoint_time(LocalDateTime.now());
        resource.setBeginTime(LocalDateTime.parse(beginTime, dateTimeFormatter));
        resource.setEndTime(LocalDateTime.parse(endTime, dateTimeFormatter));
        //--------------------------------------------------
        //由于先前已进行冲突检测，这里直接插入就行，如果没有资源冲突检测不可直接插入
        //指定资源名称
        if (null != resourceName) {
            //根据resourceName得到资源type和imp\
            //2024.6.4问题:这里map返回空了

            Map<String, Object> map = resourceMapper.selectTypeAndImp(resourceName);
            if (null == map) {
                return null;
            }
            //System.out.println(map);
            //System.out.println(map.get("type"));
            resource.setType(Math.toIntExact((Long) map.get("type")));
            resource.setImp(Math.toIntExact((Long) map.get("imp")));
            int insertResource = resourceMapper.insertResourceRecord(activity,resource.getName(),resource.getType(),resource.getImp());
            resultMap.put("count",insertResource);
            resultMap.put("resource",resource);
            return resultMap ;
        }

        //根据type和imp和aid寻找type = resourceTypeInt imp = resourceImpInt aid = 空的空闲资源
        //如果可用资源列表为空，表明无冲突但是所有符合条件的资源在当天均有使用情况，随机选择一个具体资源进行插入即可
        //更改2024.6.16 如果usable.size()为零则冲突了，不会出现在这里
/*        if (0 == usableResourceList.size()) {
            Random random = new Random();
            List<String> resourcesName = resourceMapper.selectResourceName(resourceTypeInt, resourceImpInt);
            //随机选择一个对象进行插入
            resource.setName(resourcesName.get(random.nextInt(resourcesName.size())));
            int insertCount = resourceMapper.insert(resource);
            return insertCount;
        }*/
        //如果可用资源列表不为空，表示列表中的资源在当天没有被使用的记录，取其中一个进行插入即可
        //考虑实际情况，选择 尽量使用比较空闲的资源的方案，如果存在两个可用资源，两个活动进行安排，将两个活动安排给两个资源比两个活动安排给一个资源更好一些
        Resource useResource = usableResourceList.get(0);
        resource.setName(useResource.getName());
        //int insertCount = resourceMapper.insert(resource);
        int count = resourceMapper.insertResourceRecord(activity,resource.getName(),resource.getType(),resource.getImp());
        resultMap.put("count",count);
        resultMap.put("resource",resource);
        return resultMap;

    }

    /**
     * 解决资源冲突
     * 根据活动等级
     *
     * @param activity
     * @param resourceInfo
     * @param confictResourceList
     * @return
     */
    @Override
    public Map<String, List<Resource>> settleResourceConfict(Activity activity, Map<String, String> resourceInfo, List<Resource> confictResourceList) {



        int grade = activity.getGrade();
        //时间处理
        LocalDateTime actBeginTime = LocalDateTime.parse(activity.getBeginTime(), dateTimeFormatter);
        LocalDateTime actEndTime = LocalDateTime.parse(activity.getEndTime(), dateTimeFormatter);
        //活动开始日期，不包括时间
        LocalDate actBeginDate = actBeginTime.toLocalDate();
        LocalDate actEndDate = actEndTime.toLocalDate();

        //获得冲突的活动id
        List<Integer> activityIdList = new LinkedList<>();
        for (Resource r : confictResourceList) {
            activityIdList.add(r.getAid());
        }
        //获取冲突的活动
        List<Activity> activityConfictedList = new LinkedList<>();

        for (Integer i : activityIdList) {
            if (null == i) {
                throw new ActivityCreationException("act ID 为空");
            }
            activityConfictedList.add(activityMapper.findSingleByid(i));
        }


        //目前来说这个list只会有一个元素，暂时不考虑列表含两个冲突及以上的可能（高并发环境下有可能出现）
        //根据冲突活动的grade判断
        Activity confictedActivity = activityConfictedList.get(0);
        Resource confictedResource = confictResourceList.get(0);
        //等价资源
        List<Resource> similarResourceList = resourceMapper.selectResourceByTypeAndImp(confictedResource.getType(), confictedResource.getImp(), actBeginDate);


        // 返回等价资源，包含了冲突资源
        Iterator<Resource> iterator = similarResourceList.iterator();
        while (iterator.hasNext()) {
            Resource r = iterator.next();
            // 删除冲突资源
            if (r.getId() == confictedActivity.getId() || r.getName().equals(confictedActivity.getName())) {
                iterator.remove();
                continue;
            }

            //因为返回的resource可能含有null的BeginTime
            //但这个资源也是可以用的
            if (null == r.getBeginTime() || null == r.getEndTime()){
                continue;
            }
            // 删除时间冲突资源
            if (!(actEndTime.isBefore(r.getBeginTime()) || actBeginTime.isAfter(r.getEndTime()))) {
                iterator.remove();
            }
        }

    /*
    //返回等价资源，包含了冲突资源
    //同理，需要用迭代器删除
        for (Resource r : similarResourceList) {
            //删除冲突资源
            if (r.getId() == confictedActivity.getId() || r.getName().equals(confictedActivity.getName())) {
                similarResourceList.remove(r);
                continue;
            }
            // 删除时间冲突资源
            if (!(actEndTime.isBefore(r.getBeginTime()) || actBeginTime.isAfter(r.getEndTime()))) {
                similarResourceList.remove(r);
            }

        }*/
        //对similarResourceList去重，根据resource.name
        Set<String> names = new HashSet<>();
        Iterator<Resource> similarIterator = similarResourceList.iterator();
        while (similarIterator.hasNext()) {
            Resource resource = similarIterator.next();
            if (names.add(resource.getName())) {

            } else {
                similarResourceList.remove(resource);
            }
        }
        List<Resource> usableResourceList = new LinkedList<>();

        Map<String,List<Resource>> map = new HashMap<>();
        map.put("usable",usableResourceList);
        map.put("similar",similarResourceList);
        System.out.println("map"+map);
        //根据用户输入的资源
        //分为两个部分
        //********************************************************************************
        //1.指定资源名称
        //这里如果指定了资源名称，那么资源冲突队列里面返回的资源名称也是该资源名称
        if (null != resourceInfo.get("resourceName")) {
            //如果冲突活动的等级大于等于该活动，则去查找相同类型，相同等级的资源，推荐给用户
            //之后需要进行活动等级相等的判断
            if (confictedActivity.getGrade() >= grade) {
                return map;
            }


            //-----------------------------------------------------------------------------------
            //如果冲突活动的等级小于给活动，冲突活动的资源预约被删除，由新创建的活动预约该资源
            //并且需要发送消息给冲突活动的管理者，这个活动的资源已被更高等级的活动占领，给他推荐等价资源

            int deleteCount = resourceMapper.deleteResourceById(confictedResource.getId());
            if (0 == deleteCount) {
                throw new ActivityCreationException("删除冲突资源记录失败");
            }

            int insertCount =  resourceMapper.insertResourceRecord(activity,
                    confictedResource.getName(),
                    confictedResource.getType(),
                    confictedResource.getImp());
            Resource insertResource = resourceMapper.findResource(activity,confictedResource.getName(),confictedResource.getType(),confictedResource.getImp());

            if (0 == insertCount) {
                throw new ActivityCreationException("资源记录失败");
            }

            //创建活动的资源记录插入成功后，需要给冲突活动的组织者发送消息告诉TA资源被更高等级的活动占领
            //获得组织者的用户id
            int conficetedActOrgId = activityMapper.findOrganizerByid(confictedActivity.getId());

            //通过组织者的用户id给TA发送消息
            int messageCount = messageService.sendConfictedMessageToOrg(conficetedActOrgId, confictedActivity, confictedResource,similarResourceList);

            if (0 == messageCount) {
                throw new ActivityCreationException("活动被占领的消息发送失败");
            }

            usableResourceList.add(insertResource);
            return map;

        }
        //********************************************************************************
        //2.指定资源类型和资源等级
        //处理逻辑
        Resource min = new Resource();
        Activity minActivity = new Activity();
        int minActGrade = 10;
        //获得冲突活动列表中最小的哪个，查看其是否能够被替换
        for (Activity act : activityConfictedList) {
            if (act.getGrade() < minActGrade){
                minActGrade = act.getGrade();
                minActivity = act;
            }
        }

        if (null == resourceInfo.get("resourceName")) {

            //如果冲突活动的等级大于等于该活动，则去查找相同类型，相同等级的资源，推荐给用户

            if (minActivity.getGrade() >= grade) {
                //这时map里面的两个列表都是空的，因为到这步等价资源全部都是冲突的，具体看进入这个方法的条件
                //并且里面最小等级的活动都大于等于该活动,该活动无法抢占其他活动的资源
                return map;
            }

            //-----------------------------------------------------------------------------------
            //如果冲突活动的等级小于给活动，冲突活动的资源预约被删除，由新创建的活动预约该资源
            //并且需要发送消息给冲突活动的管理者，这个活动的资源已被更高等级的活动占领，给他推荐等价资源
            //寻找冲突活动中等级最低,时间最近的活动并中


            int deleteCount = resourceMapper.deleteResourceByAid(minActivity.getId());
            if (0 == deleteCount) {
                throw new ActivityCreationException("删除冲突资源记录失败");
            }
            //todo 其他活动相关的消息是否也需要删除？

            int insertResourceCount = resourceMapper.insertResourceRecord(activity,
                    confictedResource.getName(),
                    confictedResource.getType(),
                    confictedResource.getImp());
            Resource insertResource = resourceMapper.findResource(activity,
                    confictedResource.getName(),
                    confictedResource.getType(),
                    confictedResource.getImp());

            if (0 == insertResourceCount) {
                throw new ActivityCreationException("资源记录失败");
            }

            //创建活动的资源记录插入成功后，需要给冲突活动的组织者发送消息告诉TA资源被更高等级的活动占领
            //获得组织者的用户id
            int conficetedActOrgId = activityMapper.findOrganizerByid(minActivity.getId());

            //通过组织者的用户id给TA发送消息
            int messageCount = messageService.sendConfictedMessageToOrg(conficetedActOrgId, confictedActivity, confictedResource,similarResourceList);

            if (0 == messageCount) {
                throw new ActivityCreationException("活动被占领的消息发送失败");
            }

            usableResourceList.add(insertResource);
            return map;

        }
        return map;
    }
}
